import ssl
from functools import lru_cache
from ssl import SSLContext
from typing import Optional, List, Any

from pydantic import BaseModel, Field

class DBConn(BaseModel):
    host: str = Field(..., description="host")
    port: int = Field(..., description="port")
    user: str = Field(..., description="user")
    password: str = Field(..., description="password")
    database: str = Field(..., description="database")
    minsize: int = Field(..., description="minsize")
    maxsize: int = Field(..., description="maxsize")
    charset: str = Field(..., description="charset")
    pool_recycle: int = Field(..., description="pool_recycle")


class LogSetting(BaseModel):
    """日志配置"""
    LEVEL: Optional[str] = Field('DEBUG', description='日志等级')
    PATH: str = Field(..., description='日志文件路径')
    STDOUT: Optional[bool] = Field(True, description='是否输出到标准输出')
    ROTATION: Optional[str] = Field('00:00', description='分割策略')
    RETENTION: Optional[str] = Field('30 days', description='旧的日志文件保存时间')
    COMPRESSION: Optional[str] = Field(None, description='压缩策略')


class ServiceSetting(BaseModel):
    # openapi swagger
    INCLUDE_IN_SCHEMA: Optional[bool] = Field(True, description='是否开放 openAPI')


class RedisSetting(BaseModel):
    """Redis"""
    IS_CLUSTER: Optional[bool] = Field(False, description='是否实际群模式')
    HOSTS: List[str] = Field(..., description='hosts')
    PORTS: List[int] = Field(..., description='ports')
    PASSWD: Optional[str] = Field(None, description='密码')
    SOCKET_TIMEOUT: Optional[float] = Field(10, description='socket超时时间')
    SOCKET_CONNECT_TIMEOUT: Optional[float] = Field(10, description='socket连接超时时间')
    MAX_CONNECTIONS: Optional[int] = Field(100000, description='最大连接数')
    USER: Optional[str] = Field(None, description='用户名')

class DBSetting(BaseModel):
    """MySQL"""
    IS_CLUSTER: Optional[bool] = Field(False, description='是否实际群模式')
    HOSTS: str = Field(..., description='hosts')
    PORTS: int = Field(..., description='ports')
    PASSWD: Optional[str] = Field(..., description='密码')
    USER: Optional[str] = Field(..., description='用户名')
    DATABASE: Optional[str] = Field(..., description='数据库名称')
    MAX_SIZE: Optional[int] = Field(..., description='最大连接数量')
    POOL_RECYCLE: Optional[int] = Field(..., description='连接池')
    SSL_KEY: Optional[str] = Field(None, description='连接池')
    SSL_CERT: Optional[str] = Field(None, description='连接池')


class Setting(BaseModel):
    log: LogSetting = Field(..., description='日志配置')
    service: ServiceSetting = Field(..., description='服务配置')

    redis: RedisSetting = Field(..., description='redis配置')
    db: DBSetting = Field(..., description='mysql配置')


class ORMSetting:
    def __init__(self, db: DBSetting, log_db: Any = None):
        self.db = db
        self.log_db = log_db

    @staticmethod
    def get_ssl_context(db: DBSetting) -> Optional[SSLContext]:

        if db.SSL_KEY and db.SSL_CERT:
            context = SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT)
            context.check_hostname = False
            context.load_cert_chain(certfile=db.SSL_CERT, keyfile=db.SSL_KEY)

            if db.SSL_CA:
                context.load_verify_locations(db.SSL_CA)

            context.verify_mode = ssl.CERT_REQUIRED

            return context
        else:
            return None

    def _base_orm_conf(self, apps: dict) -> dict:

        data_conn = DBConn(
            host=self.db.HOSTS, port=self.db.PORTS, user=self.db.USER,
            password=self.db.PASSWD, database=self.db.DATABASE, minsize=1,
            maxsize=self.db.MAX_SIZE, charset='utf8mb4', pool_recycle=self.db.POOL_RECYCLE
        ).model_dump()
        data_conn['ssl'] = self.get_ssl_context(self.db)

        result = {
            'connections': {
                'base_db': {
                    'engine': 'tortoise.backends.mysql',
                    'credentials': data_conn
                }
            },
            'apps': apps,
            'use_tz': False,
            'timezone': 'Asia/Shanghai'
        }

        if self.log_db:
            log_conn = DBConn(
                host=self.log_db.HOST, port=self.log_db.PORT, user=self.log_db.USER,
                password=self.log_db.PASSWD, database=self.log_db.DATABASE, minsize=1,
                maxsize=self.log_db.MAX_SIZE, charset='utf8mb4', pool_recycle=self.log_db.POOL_RECYCLE
            ).model_dump()
            log_conn['ssl'] = self.get_ssl_context(self.log_db)

            result['connections']['log_db'] = {
                'engine': 'tortoise.backends.mysql',
                'credentials': log_conn
            }

        return result

    @property
    @lru_cache
    def orm_link_conf(self) -> dict:
        result = {
            'base_db': {
                'models': [
                    'apps.models.models', "aerich.models"
                ],
                'default_connection': 'base_db'
            }
        }
        if self.log_db:
            result['log_db'] = {
                'models': [
                    'apps.models.log_db', "aerich.models"
                ],
                'default_connection': 'log_db'
            }

        return self._base_orm_conf(result)